package cn.openea.perpartner.meily.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.openea.perpartner.common.core.constant.Constants;
import cn.openea.perpartner.common.core.text.Convert;
import cn.openea.perpartner.common.redis.service.RedisCache;
import cn.openea.perpartner.meily.util.UserContext;
import cn.openea.perpartner.meily.web.entity.ActivityConfig;
import cn.openea.perpartner.meily.web.entity.ActivityProducts;
import cn.openea.perpartner.meily.web.entity.Goods;
import cn.openea.perpartner.meily.web.entity.dto.ProductDto;
import cn.openea.perpartner.meily.web.entity.vo.ProductInfo;
import cn.openea.perpartner.meily.web.entity.vo.ProductVo;
import cn.openea.perpartner.meily.web.mapper.ActivityProductsMapper;
import cn.openea.perpartner.meily.web.service.IActivityConfigService;
import cn.openea.perpartner.meily.web.service.IActivityProductsService;
import cn.openea.perpartner.meily.web.service.IBuyingRecordService;
import cn.openea.perpartner.meily.web.service.IGoodsService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * (ActivityProducts)表服务实现类
 *
 * @author Weird077
 * @since 2023-03-30 14:31:36
 */
@Slf4j
@Service("activityProductsService")
public class ActivityProductsServiceImpl extends MPJBaseServiceImpl<ActivityProductsMapper, ActivityProducts> implements IActivityProductsService {

    @Autowired
    private IGoodsService goodsService;
    @Autowired
    private IActivityConfigService configService;
    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IBuyingRecordService buyingRecordService;

    @Override
    public List<ProductVo> selectProductList(ProductInfo product) {
        MPJLambdaWrapper<ActivityProducts> wrapper = new MPJLambdaWrapper<ActivityProducts>()
                .select(ActivityProducts::getGoodsId, ActivityProducts::getGoodsPrice, ActivityProducts::getActivityName)
                .select(ActivityProducts::getDiscountPrice, ActivityProducts::getSupplyPrice, ActivityProducts::getCreateTime)
                .select(ActivityProducts::getStatus, ActivityProducts::getGoodsTop)
                .select(ActivityProducts::getGoodsId, ActivityProducts::getGoodsName, ActivityProducts::getGoodsImages)
                .select(ActivityProducts::getCategory, ActivityProducts::getSpecification)
                .select(ActivityProducts::getCustomSales, ActivityProducts::getBrand);
        if (StrUtil.isNotBlank(product.getActivityType())) {
            wrapper.eq(ActivityProducts::getActivityType, product.getActivityType());
        }
        if (StrUtil.isNotBlank(product.getStatus())) {
            wrapper.eq(ActivityProducts::getStatus, product.getStatus());
        }
        if (StrUtil.isNotBlank(product.getGoodsName())) {
            wrapper.like(Goods::getGoodsName, product.getGoodsName());
        }
        if (StrUtil.isNotBlank(product.getCategory())) {
            wrapper.like(Goods::getCategory, product.getCategory());
        }
        wrapper.orderByDesc(ActivityProducts::getGoodsTop);
        wrapper.orderByDesc(ActivityProducts::getUpdateTime);
        return selectJoinList(ProductVo.class, wrapper);
    }

    @Override
    public ActivityProducts selectByProductId(Serializable id) {

        return getById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String batchInsertProduct(ProductDto dto) {
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        ActivityConfig config = configService.selectConfigByKey(dto.getActivityType());
        if (BeanUtil.isEmpty(config)) {
            return failureMsg.append("请配置专题活动！").toString();
        }
        String activityType = config.getConfigKey();
        String activityName = config.getConfigName();
        LambdaQueryWrapper<Goods> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Goods::getGoodsId, dto.getIdList());
        List<Goods> goodsList = goodsService.list(wrapper);
        for (int i = goodsList.size() - 1; i >= 0; i--) {
            Goods goods = goodsList.get(i);
            long result = count(Wrappers.lambdaQuery(ActivityProducts.class)
                    .eq(ActivityProducts::getGoodsId, goods.getGoodsId()));
            if (result > 0) {
                goodsList.remove(goods);
                failureNum++;
                failureMsg.append("<br/>").append(failureNum).append("、商品 ").append(goods.getGoodsName()).append(" 已存在活动中");
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "共 " + failureNum + " 个商品添加失败，如下：");
        }
        if (!goodsList.isEmpty()) {
            List<ActivityProducts> productList = new ArrayList<>();
            for (Goods goods : goodsList) {
                ActivityProducts products = BeanUtil.copyProperties(goods, ActivityProducts.class);
                products.setGoodsId(null);
                products.setActivityType(activityType);
                products.setActivityName(activityName);
                products.setCreateTime(DateUtil.now());
                products.setUpdateTime(DateUtil.now());
                products.setCreateUser(UserContext.getUserId());
                products.setUpdateUser(UserContext.getUserId());
                productList.add(products);
                successNum++;
                successMsg.append("<br/>").append(successNum).append("、商品 ").append(goods.getGoodsName()).append(" 加入活动库成功");
            }
            saveBatch(productList);
            successMsg.insert(0, "共 " + successNum + " 个商品添加到'" + activityName + "'活动成功，如需修改，请前往活动库配置。数据如下：");
        }
        return successMsg.append("<br/>").append(failureMsg).toString();
    }

    @Override
    public boolean shelf(Long productId) {
        return updateById(ActivityProducts.builder()
                .goodsId(productId)
                .updateUser(UserContext.getUserId())
                .releaseTime(DateUtil.now())
                .updateTime(DateUtil.now())
                .status("已上架")
                .build());
    }


    @Override
    public boolean down(Long productId) {
        return updateById(ActivityProducts.builder()
                .goodsId(productId)
                .updateUser(UserContext.getUserId())
                .updateTime(DateUtil.now())
                .status("已下架")
                .build());
    }

    @Override
    public boolean top(Long productId) {
        LambdaQueryWrapper<ActivityProducts> wrapper = Wrappers.<ActivityProducts>lambdaQuery()
                .orderByDesc(ActivityProducts::getGoodsTop)
                .last("limit 1");
        ActivityProducts product = getOne(wrapper);
        if (BeanUtil.isEmpty(product)) {
            product.setGoodsTop("0");
        }
        if (StrUtil.isEmpty(product.getGoodsTop())) {
            product.setGoodsTop("0");
        }
        int sort = Convert.toInt(product.getGoodsTop());
        sort++;
        return updateById(ActivityProducts.builder()
                .goodsId(productId)
                .goodsTop(Convert.toStr(sort))
                .updateUser(UserContext.getUserId())
                .build());
    }

    @Override
    public boolean topCancel(Long productId) {
        return updateById(ActivityProducts.builder()
                .goodsId(productId)
                .goodsTop("0")
                .build());
    }

    @Override
    public ActivityProducts findByGoodsNo(String goodsNo) {
        LambdaQueryWrapper<ActivityProducts> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ActivityProducts::getGoodsNo, goodsNo);
        return getOne(wrapper, false);
    }

    /**
     * 从商品表查询商品分类
     *
     * @param type 商品类型
     * @return 商品分类
     */
    @Override
    public List<JSONObject> selectProductCategory(String type) {
        String redisKey = Constants.MERRY_CONFIG_KEY + type;
        List<JSONObject> typeArray = redisCache.getCacheList(redisKey);
        if (typeArray.isEmpty()) {
            //1、查询所有商品的分类
            LambdaQueryWrapper<ActivityProducts> wrapper = Wrappers.<ActivityProducts>lambdaQuery()
                    .select(ActivityProducts::getCategory).eq(ActivityProducts::getActivityType, type)
                    .ne(ActivityProducts::getCategory, "").isNotNull(ActivityProducts::getCategory);
            List<ActivityProducts> productList = list(wrapper);
            //2、将分类进行分组
            List<String> types = productList.stream().map(product -> StrUtil.split(product.getCategory(), "-")[0])
                    .collect(Collectors.toList());
            //3、去除空值
            types.removeIf(StrUtil::isBlank);
            //4、统计每个分类的数量
            JSONObject typeObj = new JSONObject();
            types.forEach(typeStr -> {
                if (typeObj.containsKey(typeStr)) {
                    typeObj.put(typeStr, typeObj.getInteger(typeStr) + 1);
                } else {
                    typeObj.put(typeStr, 1);
                }
            });
            //5、将分类和数量转换为json数组
            typeObj.forEach((key, value) -> {
                JSONObject object = new JSONObject();
                object.put("name", key);
                object.put("value", value);
                typeArray.add(object);
            });
            //6、对json数组进行排序
            typeArray.sort(Comparator.comparing(obj -> ((JSONObject) obj).getInteger("value")).reversed());
            typeArray.forEach(obj -> obj.remove("value"));
            redisCache.setCacheList(redisKey, typeArray);
            redisCache.expire(redisKey, 24, TimeUnit.HOURS);
        }
        return typeArray;
    }

    @Override
    public List<ProductVo> selectShelfProductList(ProductVo productVo) {
        MPJLambdaWrapper<ActivityProducts> wrapper = new MPJLambdaWrapper<ActivityProducts>()
                .select(ActivityProducts::getGoodsId, ActivityProducts::getGoodsPrice, ActivityProducts::getActivityName)
                .select(ActivityProducts::getDiscountPrice, ActivityProducts::getSupplyPrice, ActivityProducts::getCreateTime)
                .select(ActivityProducts::getStatus, ActivityProducts::getGoodsTop)
                .select(ActivityProducts::getGoodsNo, ActivityProducts::getGoodsName, ActivityProducts::getGoodsImages)
                .select(ActivityProducts::getCategory, ActivityProducts::getSpecification)
                .select(ActivityProducts::getCustomSales, ActivityProducts::getBrand)
                .eq(ActivityProducts::getStatus, "已上架");
        if (StrUtil.isNotBlank(productVo.getCategory())) {
            wrapper.likeRight(Goods::getCategory, productVo.getCategory());
        }
        if (StrUtil.isNotBlank(productVo.getActivityType())) {
            wrapper.eq(ActivityProducts::getActivityType, productVo.getActivityType());
        }
        if (StrUtil.isNotBlank(productVo.getSearchStr())) {
            //若商品分类不为空，模糊查询时，不需要包括category字段，否则需要
            if (StrUtil.isNotBlank(productVo.getCategory())) {
                wrapper.and(wrap -> wrap.like(Goods::getGoodsNo, productVo.getSearchStr())
                        .or().like(Goods::getGoodsName, productVo.getSearchStr())
                        .or().like(Goods::getDetail, productVo.getSearchStr())
                        .or().like(Goods::getGoodsTag, productVo.getSearchStr())
                        .or().like(Goods::getBrand, productVo.getSearchStr()));
            } else {
                wrapper.and(wrap -> wrap.like(Goods::getGoodsNo, productVo.getSearchStr())
                        .or().like(Goods::getGoodsName, productVo.getSearchStr())
                        .or().like(Goods::getDetail, productVo.getSearchStr())
                        .or().like(Goods::getCategory, productVo.getSearchStr())
                        .or().like(Goods::getGoodsTag, productVo.getSearchStr())
                        .or().like(Goods::getBrand, productVo.getSearchStr()));
            }
        }
        Short top = productVo.getTop();
        if (top == null) {
            wrapper.orderByDesc(Goods::getGoodsTop);
        } else {
            // 是否查询只有置顶的数据
            wrapper = top == 0 ? wrapper.and(wrap -> {
                wrap.eq(Goods::getGoodsTop, "")
                        .or()
                        .isNull(Goods::getGoodsTop);
            }) : wrapper.and(wrap -> {
                wrap.ne(Goods::getGoodsTop, "")
                        .isNotNull(Goods::getGoodsTop);
            });

        }
        wrapper.orderByDesc(ActivityProducts::getUpdateTime);
        List<ProductVo> list = baseMapper.selectJoinList(ProductVo.class, wrapper);
        list.forEach(item -> {
            String quantity = buyingRecordService.getGoodsSalesVolumeByGoodsNo(item.getGoodsNo());
            String customSales = item.getCustomSales();
            if (StrUtil.isEmpty(customSales)) {
                customSales = "0";
            }
            int soldNum = Convert.toInt(quantity) + Convert.toInt(customSales);
            item.setSoldNum(Convert.toStr(soldNum));
        });
        return list;
    }

    /**
     * 生成一个不重复的ID
     */
    public String getUuiD(int length, String preffix) {
        //timestamp为当前时间戳
        long timestamp = (new Date()).getTime();
        length = length - 13;
        String str = "";
        String[] str_arr = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
        for (int i = 0; i < length; i++) {
            //生成0-62之间的随机数
            int r = Convert.toInt(Math.random() * 9);
            str += str_arr[r];
        }
        String res_str = preffix + str + timestamp;
        return res_str;
    }
}

